package cc.iteachyou.template.utils;

import cc.iteachyou.template.TemplateEngine;
import cc.iteachyou.template.TemplateEngineFactory;
import cc.iteachyou.template.configuration.TemplateEngineConfiguration;
import cc.iteachyou.template.dom.*;
import cc.iteachyou.template.taglib.directives.ForDirectiveHandler;
import cc.iteachyou.template.taglib.directives.IfDirectiveHandler;
import cc.iteachyou.template.taglib.directives.IncludeDirectiveHandler;
import cc.iteachyou.template.taglib.directives.ReplaceDirectiveHandler;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.HashUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import org.jsoup.Jsoup;
import org.jsoup.nodes.*;
import org.jsoup.select.Elements;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class TemplateHelper {
    private TemplateEngineConfiguration configuration;
    private static TemplateHelper helper = null;

    /**
     * 构造函数
     */
    private TemplateHelper(){}

    /**
     * 构造函数
     */
    private TemplateHelper(TemplateEngineConfiguration configuration){
        this.configuration = configuration;
    }

    /**
     * 获取模板引擎助手实例
     * @return
     */
    public static TemplateHelper getInstance(TemplateEngineConfiguration configuration){
        if(helper == null){
            helper = new TemplateHelper(configuration);
        }
        return helper;
    }

    /**
     * 读取模板文件内容
     * @param templateName 模板文件名称
     * @return 文件内容
     */
    public String read(String templateName){
        String content = "";
        // classpath 资源
        if(configuration.getPrefix().startsWith(configuration.CLASSPATH_PREFIX)){
            String directory = configuration.getPrefix().replace(configuration.CLASSPATH_PREFIX, "");
            URL templateURL = this.getClass().getClassLoader().getResource(directory + templateName + configuration.getSuffix());
            File templateFile = new File(templateURL.getFile());

            content = FileUtil.readUtf8String(templateFile);
        } else if (configuration.getPrefix().startsWith(configuration.FILESYSTEM_PREFIX)) { // 文件系统

        }
        return content;
    }

    /**
     * 解析HTML字段串为Document
     * @param html html字符
     * @return
     */
    public Document parse(String html){
        Document document = Jsoup.parse(html);
        return document;
    }

    /**
     * 创建虚拟DOM树
     * @param document
     */
    public VirtualDOMTree createVirtualDOM(Document document) {
        Element root = document.root();

        // 文档类型
        DocumentType documentType = document.documentType();
        VirtualDocType docType = null;
        if (documentType!=null){
            docType = new VirtualDocType();
            docType.setDocType(documentType.toString());
        }


        List<Node> elements = root.childNodes();
        List<VirtualDOMNode> nodes = cascadeCreateVirtualNode(elements);

        VirtualDOMTree virtualDOMTree = VirtualDOMTree.builder().tree(nodes).build();
        virtualDOMTree.setDocType(docType);
        return virtualDOMTree;
    }

    /**
     * 递归创建虚拟DOM节点
     * @param elements
     * @return
     */
    private List<VirtualDOMNode> cascadeCreateVirtualNode(List<Node> elements){
        List<VirtualDOMNode> nodes = new ArrayList<>();
        t: for (Node node : elements) {
            if(node instanceof Element) {
                Element element = (Element) node;
                VirtualDOMElementNode vnode = new VirtualDOMElementNode();
                vnode.setHash(IdUtil.objectId());
                vnode.setId(element.id());
                vnode.setName(element.tagName());

                if (element.tag().isSelfClosing()) {
                    vnode.setIsSingleTag(true);
                }

                // 解析属性
                Attributes attributes = element.attributes();
                if (attributes != null && attributes.size() > 0) {
                    List<VirtualDOMAttr> attrs = new ArrayList<>();
                    for (Attribute attribute : attributes) {
                        VirtualDOMAttr vattr = new VirtualDOMAttr();
                        vattr.setName(attribute.getKey());
                        vattr.setValue(attribute.getValue());

                        if (("dreamer-cms:fragment").equals(vattr.getName())){
                            continue ;
                        }

                        String attrname = vattr.getName();
                        if (configuration.SYSTEM_DIRECTIVES.containsKey(attrname.toLowerCase())) {// 系统属性
                            vattr.setType(VirtualDOMAttr.VirtualDOMAttrTypeEnum.SYSTEM);
                            vattr.setHandler(configuration.SYSTEM_DIRECTIVES.get(attrname.toLowerCase()));
                            if(vattr.getHandler() instanceof ForDirectiveHandler){
                                vnode.setLoopable(true);
                                Pattern pattern = Pattern.compile("(.*)?[\\s]{0,}:[\\s]{0,}((#.*)|(\\d))");
                                Matcher matcher = pattern.matcher(vattr.getValue());
                                if(!matcher.find()){
                                    throw new RuntimeException("For loop syntax error.");
                                }
                                String item = matcher.group(1);
                                String list = matcher.group(2);
                                vnode.setLoopItemKey(item.trim());
                                vnode.setLoopArray(list.trim());
                                continue;
                            } else if(vattr.getHandler() instanceof IfDirectiveHandler){
                                vnode.setBranchable(true);
                                vnode.setBranchData(vattr.getValue());
                                continue;
                            }

                            if (vattr.getHandler() instanceof IncludeDirectiveHandler || vattr.getHandler() instanceof ReplaceDirectiveHandler){
                                String value = vattr.getValue();
                                int i = value.indexOf(".", value.indexOf(".")+ 1);
                                String templateName = value.substring(value.indexOf("/")+1, i);
                                String fragmentValue = value.substring(value.indexOf(":")+1);
                                // 获取模板引擎助手实例
                                TemplateHelper templateHelper = TemplateHelper.getInstance(configuration);
                                CacheHelper cacheHelper = CacheHelper.getInstance();

                                String content = null;
                                // 如果需要缓存模板内容，则从缓存中获取
                                if(configuration.getCache()){
                                    cacheHelper.get(templateName);
                                }

                                if(StrUtil.isBlank(content)) {
                                    // 通过助手读取模板内容
                                    content = templateHelper.read(templateName);
                                }

                                // 加入缓存
                                cacheHelper.set(templateName, content);
                                // 通过助手解析html内容
                                Document document = templateHelper.parse(content);
                                Elements elementss = document.getElementsByAttributeValue("dreamer-cms:fragment", fragmentValue);

                                List<Node> includeList = new ArrayList<>(elementss);

                                List<VirtualDOMNode> includeNodes = cascadeCreateVirtualNode(includeList);

                                if (vattr.getHandler() instanceof IncludeDirectiveHandler){
                                    vnode.setChildren(includeNodes);
                                }else {
                                    nodes.addAll(includeNodes);
                                    continue t;
                                }

                            }

                        } else if (configuration.CUSTOM_DIRECTIVES.containsKey(attrname.toLowerCase().toLowerCase())) {// 自定义属性
                            vattr.setType(VirtualDOMAttr.VirtualDOMAttrTypeEnum.CUSTOM);
                            vattr.setHandler(configuration.CUSTOM_DIRECTIVES.get(attrname.toLowerCase()));
                        } else {// 原生
                            vattr.setType(VirtualDOMAttr.VirtualDOMAttrTypeEnum.NATIVE);
                        }

                        attrs.add(vattr);
                    }
                    vnode.setAttrs(attrs);
                }

                // 解析子节点
                List<Node> children = element.childNodes();
                if (children != null && children.size() > 0) {
                    List<VirtualDOMNode> subchildren = cascadeCreateVirtualNode(children);
                    vnode.setChildren(subchildren);
                }
                nodes.add(vnode);
            } else if(node instanceof TextNode){
                TextNode element = (TextNode) node;
                if(StrUtil.isBlank(element.text())){
                    continue;
                }
                VirtualDOMTextNode tnode = new VirtualDOMTextNode();
                tnode.setHash(IdUtil.objectId());
                tnode.setContent(element.text());
                nodes.add(tnode);
            } else if(node instanceof DataNode){
                DataNode element = (DataNode) node;
                if(StrUtil.isBlank(element.getWholeData())){
                    continue;
                }
                VirtualDOMTextNode tnode = new VirtualDOMTextNode();
                tnode.setHash(IdUtil.objectId());
                tnode.setContent(element.getWholeData());
                nodes.add(tnode);
            }
        }
        return nodes;
    }
}
